package com.kexilo.core.common.config;

import com.github.benmanes.caffeine.cache.stats.CacheStats;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 缓存监控组件
 * 
 * @author Kexilo
 */
@Component
public class CacheMonitor {
    
    private static final Logger log = LoggerFactory.getLogger(CacheMonitor.class);

    @Autowired
    private CacheManager cacheManager;

    @Autowired(required = false)
    private RedisTemplate<String, Object> redisTemplate;

    private final AtomicLong cacheHitCount = new AtomicLong(0);
    private final AtomicLong cacheMissCount = new AtomicLong(0);
    private final DecimalFormat df = new DecimalFormat("#.##%");

    /**
     * 定时监控缓存状态（每5分钟）
     */
    @Scheduled(fixedRate = 300000)
    public void monitorCacheStats() {
        try {
            log.info("=== 缓存监控报告 ===");
            
            // 监控所有缓存
            cacheManager.getCacheNames().forEach(cacheName -> {
                Cache cache = cacheManager.getCache(cacheName);
                if (cache != null) {
                    monitorSingleCache(cacheName, cache);
                }
            });
            
            // 监控整体缓存命中率
            monitorOverallStats();
            
            // 监控Redis连接状态
            monitorRedisConnection();
            
            log.info("=== 缓存监控报告结束 ===");
        } catch (Exception e) {
            log.error("缓存监控异常", e);
        }
    }

    /**
     * 监控单个缓存
     */
    private void monitorSingleCache(String cacheName, Cache cache) {
        try {
            if (cache instanceof CaffeineCache) {
                monitorCaffeineCache(cacheName, (CaffeineCache) cache);
            } else if (cache instanceof RedisCache) {
                monitorRedisCache(cacheName, (RedisCache) cache);
            }
        } catch (Exception e) {
            log.warn("监控缓存 {} 异常: {}", cacheName, e.getMessage());
        }
    }

    /**
     * 监控Caffeine缓存
     */
    private void monitorCaffeineCache(String cacheName, CaffeineCache caffeineCache) {
        try {
            com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache = 
                caffeineCache.getNativeCache();
            CacheStats stats = nativeCache.stats();
            
            long hitCount = stats.hitCount();
            long missCount = stats.missCount();
            long totalCount = hitCount + missCount;
            double hitRate = totalCount > 0 ? (double) hitCount / totalCount : 0.0;
            
            log.info("Caffeine缓存 [{}] - 命中: {}, 失效: {}, 命中率: {}, 大小: {}", 
                    cacheName, hitCount, missCount, df.format(hitRate), 
                    nativeCache.estimatedSize());
                    
            // 记录到全局统计
            cacheHitCount.addAndGet(hitCount);
            cacheMissCount.addAndGet(missCount);
            
        } catch (Exception e) {
            log.warn("监控Caffeine缓存异常: {}", e.getMessage());
        }
    }

    /**
     * 监控Redis缓存
     */
    private void monitorRedisCache(String cacheName, RedisCache redisCache) {
        try {
            // Redis缓存的统计信息需要通过其他方式获取
            // 这里可以通过Redis命令获取一些基本信息
            log.info("Redis缓存 [{}] - 运行正常", cacheName);
        } catch (Exception e) {
            log.warn("监控Redis缓存异常: {}", e.getMessage());
        }
    }

    /**
     * 监控整体缓存统计
     */
    private void monitorOverallStats() {
        long totalHit = cacheHitCount.get();
        long totalMiss = cacheMissCount.get();
        long total = totalHit + totalMiss;
        
        if (total > 0) {
            double overallHitRate = (double) totalHit / total;
            log.info("整体缓存统计 - 总命中: {}, 总失效: {}, 整体命中率: {}", 
                    totalHit, totalMiss, df.format(overallHitRate));
        }
    }

    /**
     * 监控Redis连接状态
     */
    private void monitorRedisConnection() {
        if (redisTemplate != null) {
            try {
                redisTemplate.opsForValue().get("health:check");
                log.info("Redis连接状态: 正常");
            } catch (Exception e) {
                log.error("Redis连接异常: {}", e.getMessage());
            }
        }
    }

    /**
     * 缓存事件监听器
     */
    @EventListener
    public void handleCacheEvent(Object event) {
        // 这里可以监听缓存相关事件
        log.debug("缓存事件: {}", event.getClass().getSimpleName());
    }

    /**
     * 获取缓存统计信息
     */
    public Map<String, Object> getCacheStatistics() {
        Map<String, Object> stats = new HashMap<>();
        
        // 整体统计
        long totalHit = cacheHitCount.get();
        long totalMiss = cacheMissCount.get();
        long total = totalHit + totalMiss;
        double hitRate = total > 0 ? (double) totalHit / total : 0.0;
        
        stats.put("totalHit", totalHit);
        stats.put("totalMiss", totalMiss);
        stats.put("hitRate", hitRate);
        
        // 各个缓存的统计
        Map<String, Object> cacheDetails = new HashMap<>();
        cacheManager.getCacheNames().forEach(cacheName -> {
            Cache cache = cacheManager.getCache(cacheName);
            if (cache instanceof CaffeineCache) {
                CaffeineCache caffeineCache = (CaffeineCache) cache;
                com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache = 
                    caffeineCache.getNativeCache();
                CacheStats cacheStats = nativeCache.stats();
                
                Map<String, Object> detail = new HashMap<>();
                detail.put("type", "Caffeine");
                detail.put("hitCount", cacheStats.hitCount());
                detail.put("missCount", cacheStats.missCount());
                detail.put("size", nativeCache.estimatedSize());
                detail.put("hitRate", cacheStats.hitRate());
                
                cacheDetails.put(cacheName, detail);
            }
        });
        
        stats.put("cacheDetails", cacheDetails);
        return stats;
    }

    /**
     * 清空统计信息
     */
    public void resetStatistics() {
        cacheHitCount.set(0);
        cacheMissCount.set(0);
        log.info("缓存统计信息已重置");
    }
}
